package com.sky.module.system.file.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sky.common.domain.form.FileQueryForm;
import com.sky.common.exception.SkyException;
import com.sky.common.exception.SkySecurityException;
import com.sky.module.suppot.file.domain.entity.FileEntity;
import com.sky.module.suppot.file.domain.vo.FileEntityVo;
import com.sky.module.suppot.file.s3.OssProperties;
import com.sky.module.suppot.file.s3.S3OssClient;
import com.sky.module.suppot.file.service.FileStorageService;
import com.sky.module.system.file.dao.FileMapper;
import com.sky.module.system.user.domain.entity.User;
import com.sky.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.print.attribute.standard.MediaSize;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;


@Slf4j
@Service
@Transactional
public class FileServiceImpl implements FileService {

    /**
     * 文件上传
     *
     * @param file 文件上传对象
     * @param module 文件夹名称
     * @return
     */
    @Resource
    private OssProperties ossProperties;


    @Autowired
    private S3OssClient s3OssClient;


    /***
     * @description 云端文件上传
     * @param file
     * @param
     *
     * @return void
     * @date 2023/3/2 3:46
     *
     */
    private Result uploadCloud(MultipartFile file, String module) {
//        String originalFilename = file.getOriginalFilename();
//        // 根据 获取文件后缀
//        String extension = FilenameUtils.getExtension(originalFilename);
//
//        String fileKey = UUID.randomUUID().toString() + "." + extension;
////        objectName  bucket 加上目录 加上fileKey
//        //使用当前日期进行分类管理
//        String datePath = new DateTime().toString("yyyy/MM/dd");
//        //构建文件名
//        String newFileName = module + "/" + datePath + "/" + fileKey;
//        // 如果
////        if (!s3OssClient.getAmazonS3().doesBucketExistV2(ossProperties.getBucketName())) {
////            s3OssClient.createBucket(ossProperties.getBucketName());
////            s3OssClient.getAmazonS3().ac
////        }
//        try {
//            s3OssClient.putObject(ossProperties.getBucketName(), newFileName, file.getInputStream());
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.info("文件上传失败");
//        }
//        String fileUrl = s3OssClient.getObjectURL(ossProperties.getBucketName(), newFileName);
        uploadLocal(null, "");

        return null;
    }

    /***
     * @description 基于s3 协议的文件上传 & 本地的文件上传
     * @param file
     * @param module 文件上传目录前缀

     * @return java.lang.String
     * @date 2023/3/2 1:54
     *
     */


    @Autowired
    private FileMapper fileMapper;

    @Override
    public Result uploadFile(MultipartFile file, String module) {
        // 根据mode 值来判断  local 或者 cloud 来判断注入哪个实现类
        // 如果是cloud 就会根据条件注解去注入基于s3协议的文件上传
        Result<FileEntity> result = fileStorageService.fileUpload(file, module);
        if (!result.getSuccess()) {
            return result;
        }
        FileEntity fileEntity = result.getData();
        //  http://119.91.64.46:9000/fileKey
        // ip + bucket + fileKey
        // 组装我们数据返回给前端
        Result<String> res = fileStorageService.getFileUrl(fileEntity.getFileKey());
        String url = res.getData();
        FileEntityVo fileEntityVo = FileEntityVo.builder()
                .fileUrl(url)
                .fileSize(fileEntity.getFileSize())
                .fileKey(fileEntity.getFileKey())
                .fileName(fileEntity.getFileName())
                .fileType(fileEntity.getFileType())
                .build();
        fileMapper.insert(fileEntity);
        fileEntityVo.setId(fileEntity.getId());
        return Result.ok(fileEntityVo).message("上传成功");


    }

    public static void main(String[] args) {
        System.out.println(1 << 2);
        final HashMap<Object, Object> map = new HashMap<>();
    }

    /***
     * @description 本地文件上传测试
     * @param
     * @param folder
     * @return java.lang.String
     * @date 2023/3/2 2:37
     *
     */
    private Result uploadLocal(MultipartFile multipartFile, String folder) {
//        //
//        final String originalFilename = multipartFile.getOriginalFilename();
//        if (multipartFile == null) {
//            throw new SkySecurityException("文件不能为空", 500);
//        }
//        // 如果给的目录不是斜杠结尾 就加一个结尾
//        if (!folder.endsWith("/")) {
//            folder = folder + "/";
//        }
//
//        // 加上  /home/smart_admin_v2/upload/avatar/
//        String filePath = localPath + folder;
//        final File diretory = new File(filePath);
//        if (!diretory.exists()) { // filepath 文件目录不存在的话，就创建这个目录
////         如果目录不存在就进行创建
//            diretory.mkdirs();
//        }
//
//
//        // 新文件名  87591a89e4234fd895108f5ed6661b08_20230302095931.jpg 防止文件重复
//        String newFileName = this.generateFileName(originalFilename);
//        //     /home/ccc/uuid.jpg
//        String fileKey = filePath + newFileName;
//        // 创建一个临时文件  filepath + filekey 就是目录加上文件名字 创建文件
////         /home/smart_admin_v2/upload/avatar/87591a89e4234fd895108f5ed6661b08_20230302095931.jpg
//        final File fileTemp = new File(new File(filePath + newFileName).getAbsolutePath());
//        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//        String username = user.getUsername();
//
//        FileEntityVo fileEntityVo = null;
////          数据库不需要保存文件路径 只需要保存public key 文件路径即可，因为域名有可能不同，使用的不同的oss
//        try {
//            String fileType = FilenameUtils.getExtension(originalFilename);
//
//            String url = ossProperties.getEndpoint() + fileKey;
//            multipartFile.transferTo(fileTemp);
////
////            final String url = this.genernateUrl(fileKey);
//            fileEntityVo = FileEntityVo.builder()
//                    .fileKey(fileKey)
//                    .fileName(originalFilename)
//                    .fileSize(multipartFile.getSize())
//                    .fileType(fileType)
//                    .fileUrl(url)
//                    .build();
//
////            fileEntity = FileEntity.builder().fileKey(fileKey)
////                    .fileName(originalFilename)
////                    .fileSize(multipartFile.getSize())
////                    .fileType(FilenameUtils.getExtension(originalFilename))
////                    .folderType(1) // 文件夹 类型
////                    .createTime(LocalDateTime.now())
//////                    .creatorName(username)
//////                    .fileUrl(url)
////                    .build();
////            fileMapper.insert(fileEntity);
//        } catch (Exception e) {
//            // 如果保存失败 就删除之前已经创建好的临时文件
//            if (fileTemp.exists() && fileTemp.isFile()) {
//                fileTemp.delete();
//            }
//            log.error("文件上传失败");
//
//        }
//        log.info("上传文件成功 fileName :" + multipartFile.getOriginalFilename() + "创建人是" + username);
//        return Result.ok(fileEntityVo).message("success");

        return null;

    }

    /***
     * @description 生成文件url
     *
     *
     * @return java.lang.String
     * @date 2023/3/2 3:38
     *
     */
    private String genernateUrl(String fileKey) {
//            TODO 先固定写死， 后期再修改
        String url = "http://localhost:8888/" + fileKey;

        return url;
    }

    //    @Override
//    public String upload(MultipartFile file, String module) {
//        //获取地域节点
//        String endPoint = ossProperties.getEndPoint();
//        //获取AccessKeyId
//        String keyId = ossProperties.getKeyId();
//        //获取AccessKeySecret
//        String keySecret = ossProperties.getKeySecret();
//        //获取BucketName
//        String bucketName = ossProperties.getBucketName();
//        try {
//            //创建OSSClient实例
//            OSS ossClient = new OSSClientBuilder().build(endPoint, keyId,
//                    keySecret);
//            //上传文件流
//            InputStream inputStream = file.getInputStream();
//            //获取旧名称
//            String originalFilename = file.getOriginalFilename();
//            //获取文件后缀名
//            String extension = FilenameUtils.getExtension(originalFilename);
//            //将文件名重命名
//            String newFileName = UUID.randomUUID().toString()
//                    .replace("-", "") + "." + extension;
//            //使用当前日期进行分类管理
//            String datePath = new DateTime().toString("yyyy/MM/dd");
//            //构建文件名
//            newFileName = module + "/" + datePath + "/" + newFileName;
//            //调用OSS文件上传的方法
//            ossClient.putObject(bucketName, newFileName, inputStream);
//            //关闭OSSClient
//            ossClient.shutdown();
//            //返回文件地址
//            return "https://" + bucketName + "." + endPoint + "/" + newFileName;
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }
//    @Override
//    public void deleteFile(String url) {
//        //获取地域节点
//        String endPoint = ossProperties.getEndPoint();
//        //获取AccessKeyId
//        String keyId = ossProperties.getKeyId();
//        //获取AccessKeySecret
//        String keySecret = ossProperties.getKeySecret();
//        //获取BucketName
//        String bucketName = ossProperties.getBucketName();
//        try {
//            //创建OSSClient实例
//            OSS ossClient = new OSSClientBuilder().build(endPoint, keyId,
//                    keySecret);
//            //组装文件地址
//            String host = "https://" + bucketName + "." + endPoint + "/";
//            //获取文件名称
//            String objectName = url.substring(host.length());
//            //删除文件
//            ossClient.deleteObject(bucketName, objectName);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }

    /***
     * @description 分页条件查询文件信息
     * @param fileQueryForm
     * @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.sky.module.suppot.file.domain.entity.FileEntity>
     * @date 2023/3/1 15:00
     *
     */
    @Override
    public Page<FileEntity> queryPage(FileQueryForm fileQueryForm) {
        final Page<FileEntity> entityPage = new Page<>(fileQueryForm.getPageNum(), fileQueryForm.getPageSize());
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(fileQueryForm.getFileName()), FileEntity::getFileName, fileQueryForm.getFileName());
        wrapper.like(StringUtils.isNotBlank(fileQueryForm.getFileKey()), FileEntity::getFileKey, fileQueryForm.getFileKey());
        wrapper.like(StringUtils.isNotBlank(fileQueryForm.getFileType()), FileEntity::getFileType, fileQueryForm.getFileType());
        wrapper.like(StringUtils.isNotBlank(fileQueryForm.getCreatorName()), FileEntity::getCreatorName, fileQueryForm.getCreatorName());
//         大于、
        wrapper.ge(!ObjectUtils.isEmpty(fileQueryForm.getCreateTimeBegin()), FileEntity::getCreateTime, fileQueryForm.getCreateTimeBegin());
        wrapper.le(!ObjectUtils.isEmpty(fileQueryForm.getCreateTimeEnd()), FileEntity::getUpdateTime, fileQueryForm.getCreateTimeEnd());

        final Page<FileEntity> page = fileMapper.selectPage(entityPage, wrapper);

        return page;
    }

    /***
     * @description 根据文件key进行文件的删除 cloud 和数据库
     * @param fileKey
     * @return void
     * @date 2023/3/1 15:01
     *
     */
    @Override
    public void delete(String fileKey) {
        // 删除本地的，然后根据 本次存储类或者是云存储类去删除对应的文件
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FileEntity::getFileKey, fileKey);
        fileMapper.delete(wrapper);

//        TODO 删除 云key  和本地文件
        fileStorageService.delete(fileKey);


    }


    @Autowired
    private FileStorageService fileStorageService;

    /***
     * @description 有过期时间的获取
     * @param fileKey
     * @return com.sky.utils.Result<?>
     * @date 2023/3/2 9:02
     *
     */
    @Override
    public Result<?> getFileUrl(String fileKey) {

        if (StringUtils.isEmpty(fileKey)) {
            return Result.error().message("filekey不能为空");
        }

        // 基于条件注解的方式
        // 也就是如果使用local的当然就不能看云存储的文件了
        // 会注入2种不同的对象 一个是本地 还有一个基于S3 协议的云上传

        Result<String> result = fileStorageService.getFileUrl(fileKey);
        if (!result.getSuccess()) {
            return Result.error().message("获取文件url失败");
        }

//        TODO 放在redis 进行缓存


//        final Date expireDate = new Date(System.currentTimeMillis() + expire);
//        s3OssClient.getAmazonS3().getUrl()

        return Result.ok(result.getData()).message("获取到文件url");
    }

}
